home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 1122 / 1122.xpi / chrome / tabmixplus.jar / content / tabmixplus / links / contentLinks.js next >
Encoding:
JavaScript  |  2009-09-11  |  25.7 KB  |  695 lines

  1. /*
  2.  * chrome://tabmixplus/content/links/contentLinks.js
  3.  *
  4.  * original code by Bradley Chapman
  5.  * modified and developped by Hemiola SUN
  6.  * modified again by Bradley Chapman
  7.  *
  8.  */
  9.  
  10. /**
  11.  * @brief Open the given link node in the current window.
  12.  *
  13.  * @param event        A valid event union.
  14.  * @param linkNode    The DOM node containing the URL to open.
  15.  * @param currentTab    A Boolean value. If true, the URL will be opened
  16.  *            within the current tab. If false, it will be
  17.  *            opened in a new tab.
  18.  * @returns        True if the function opened a URL, or the value
  19.  *            of handleLinkClick() if it chose not to.
  20.  *
  21.  */
  22. function TMP_howToOpen(event, linkNode, currentTab) {
  23.   // this helper function parses the event union for us
  24.   // and makes a better determination of how a link will
  25.   // be opened
  26.   var where = whereToOpenLink(event);
  27.  
  28.   if (where == "save" || where == "window" ) {
  29.     handleLinkClick(event, linkNode.href, linkNode);
  30.     return true;
  31.   }
  32.  
  33.   try {
  34.     urlSecurityCheck(linkNode.href, linkNode.ownerDocument.nodePrincipal);
  35.   }
  36.   catch(ex) {
  37.     return false;
  38.   }
  39.  
  40.   var postData = { };
  41.   var url = getShortcutOrURI(linkNode.href, postData);
  42.   if (!url)
  43.     return true;
  44.  
  45.   // if where is "tab", "tabshifted", "current" callers will control the inversion of currentTab
  46.   try {
  47.     var doc = event.target.ownerDocument;  
  48.     if (currentTab) {
  49.       var referrerURI = doc ? doc.documentURIObject : null;
  50.       window.loadURI(url, referrerURI, postData.value, false);
  51.     } 
  52.     else {
  53.       window.openNewTabWith(url, doc, null, event, false);
  54.     }
  55.   } catch (e) {}
  56.   event.preventDefault();
  57.   return !currentTab;
  58. }
  59.  
  60. /**
  61.  * @brief Check for certain JavaScript strings inside an attribute.
  62.  *
  63.  * @param attr            The attribute to check.
  64.  * @param string        The string to check for.
  65.  * @returns            true if the strings are present, false if they aren't.
  66.  *
  67.  */
  68. function TMP_checkAttr(attr, string) {
  69.    if (typeof(attr) == "string") return attr.indexOf(string) == 0;
  70.    return false;
  71. }
  72.  
  73. /**
  74.  * @brief Check if link refers to external domain.
  75.  *
  76.  * @param target  The target link.
  77.  * @param curpage  The current page url
  78.  * @returns       current domain and target domain
  79.  *
  80.  */
  81. function checkDomain(curpage, target) {
  82.   function getDomain(url) {
  83.     if (typeof(url) != "string")
  84.       url = url.toString();
  85.  
  86.     if (url.match(/^file:/))
  87.       return "local_file";
  88.  
  89.     if (url.match(/^http/)) {
  90.       url = gIOService.newURI(url, null, null);
  91.  
  92.       // catch redirect
  93.       if (url.path.match(/^\/r\/\?http/))
  94.         url = gIOService.newURI(url.path.substr("/r/?".length), null, null);
  95.       var host = url.hostPort.split(".");
  96.       //XXX      while (host.length > 3) <---- this make problem to site like yahoo mail.yahoo.com ard.yahoo.com need
  97.       while (host.length > 2)
  98.         host.shift();
  99.       return host.join(".");
  100.     }
  101.     return null;
  102.   }
  103.   return {current: getDomain(curpage), target: getDomain(target)};
  104. }
  105.  
  106. /**
  107.  * @brief Handle left-clicks inside a browser viewport.
  108.  *
  109.  * This function is the primary entry point for all left-clicks on a browser
  110.  * page; we triage and sort such clicks and handle the ones we want and pass
  111.  * on the ones that we don't.
  112.  *
  113.  * @param event            A valid event union.
  114.  * @param fieldNormalClicks    A Boolean value. If true, we will handle all left-clicks
  115.  *                that invoke this function. If false, we will only handle
  116.  *                the ones that require additional legwork (i.e. locked tabs).
  117.  * @returns            Either the return value of __contentAreaClick(), or the
  118.  *                return value of handleLinkClick(), or true if the function
  119.  *                was passed an event it could not handle.
  120.  */
  121. function TMP_contentAreaClick(event, fieldNormalClicks) {
  122.   var targetPref = gTabmixPrefs.getIntPref("extensions.tabmix.speLink");
  123.   var linkTarget = gTabmixPrefs.getBoolPref("extensions.tabmix.linkTarget");
  124.   var suppressTabs = gTabmixPrefs.getBoolPref("extensions.tabmix.enablefiletype")
  125.  
  126.   if (!event.isTrusted || event.getPreventDefault()) {
  127.      return true;
  128.   }
  129.   var target = event.target;
  130.   var linkNode;
  131.   var where = whereToOpenLink(event);
  132.  
  133.   if (target instanceof HTMLButtonElement ||
  134.       target instanceof HTMLInputElement) {
  135.     if (typeof(SubmitToTab)!='undefined' && SubmitToTab.contentAreaClick(event) == false) {
  136.       return false;
  137.     }
  138.   }
  139.  
  140.   if (target instanceof HTMLAnchorElement ||
  141.       target instanceof HTMLAreaElement ||
  142.       target instanceof HTMLLinkElement) {
  143.     if (target.hasAttribute("href"))
  144.       linkNode = target;
  145.  
  146.      // xxxmpc: this is kind of a hack to work around a Gecko bug (see bug 266932)
  147.      // we're going to walk up the DOM looking for a parent link node,
  148.      // this shouldn't be necessary, but we're matching the existing behaviour for left click
  149.      var parent = target.parentNode;
  150.      while (parent) {
  151.        if (parent instanceof HTMLAnchorElement ||
  152.            parent instanceof HTMLAreaElement ||
  153.            parent instanceof HTMLLinkElement) {
  154.            if (parent.hasAttribute("href"))
  155.              linkNode = parent;
  156.        }
  157.        parent = parent.parentNode;
  158.      }
  159.   }
  160.   else {
  161.     linkNode = event.originalTarget;
  162.     while (linkNode && !(linkNode instanceof HTMLAnchorElement))
  163.       linkNode = linkNode.parentNode;
  164.     // <a> cannot be nested.  So if we find an anchor without an
  165.     // href, there is no useful <a> around the target
  166.     if (linkNode && !linkNode.hasAttribute("href"))
  167.       linkNode = null;
  168.     else if (linkNode && linkNode.hasAttribute("href"))
  169.       target = linkNode;
  170.   }
  171.  
  172.   if (!linkNode)
  173.     return __contentAreaClick(event, fieldNormalClicks);
  174.  
  175.   // Check if new tab already opened from onclick event // 2006-09-26
  176.   if (target.hasAttribute("onclick") && gBrowser.contentDocument.location.href != document.commandDispatcher.focusedWindow.top.location.href)
  177.     return true;
  178.  
  179.   // Check if link refers to external domain.
  180.   // Get current page url
  181.   // if user click a link when the psage is reloading linkNode.ownerDocument.location can be null
  182.   var curpage = linkNode.ownerDocument.location ? linkNode.ownerDocument.location.href : gBrowser.currentURI.spec;
  183.   var domain = checkDomain(curpage, target);
  184.   var targetDomain = domain.target;
  185.   var currentDomain = domain.current;
  186.  
  187.   var openT = linkNode.getAttribute("target");
  188.   // If link has no target attribute, check if there is a <base> with a target attribute
  189.   if (!openT) {
  190.     var b = document.commandDispatcher.focusedWindow.document.getElementsByTagName("base");
  191.     if (b.length > 0)
  192.       openT = b[0].getAttribute("target");
  193.   }
  194.  
  195.   if (linkNode.getAttribute("rel") == "sidebar" ||
  196.       openT == "_search" ||
  197.       linkNode.getAttribute("href").indexOf("mailto:") > -1) {
  198.     return __contentAreaClick(event, fieldNormalClicks);
  199.   }
  200.  
  201.   /*
  202.    * prevents tab form opening when clicking Greasemonkey script
  203.    */
  204.   if (TMP_isGreasemonkeyScript(event, target))
  205.     return true;
  206.  
  207.   /*
  208.    * prevent tabs from opening if left-clicked link ends with given filetype or matches regexp;
  209.    * portions were taken from disable target for downloads by cusser
  210.    *
  211.    */
  212.   if (TMP_suppressTabsOnFileDownload(event, target, linkNode, suppressTabs)) {
  213.       // don't do anything if we are on gmail and let gmail to take care of the download
  214.       var isGmail = /^(http|https):\/\/mail.google.com/.test(target.ownerDocument.location.href);
  215.       var isHttps = /^https/.test(target);
  216.       if (isGmail || isHttps)
  217.          return true;
  218.  
  219.       return TMP_howToOpen(event, linkNode, true);
  220.   }
  221.  
  222.   /*
  223.    * force a middle-clicked link to open in the current tab if certain conditions
  224.    * are true. See the function comment for more details.
  225.    *
  226.    */
  227.   if (TMP_divertMiddleClick(event, linkNode, gBrowser.mCurrentTab, currentDomain, targetDomain,
  228.                             targetPref, gTabmixPrefs.getBoolPref("extensions.tabmix.middlecurrent"))) {
  229.     return TMP_howToOpen(event, linkNode, true);
  230.   }
  231.  
  232.   // catch other middle & right click
  233.   if (event.button != 0) {
  234.     handleLinkClick(event, linkNode.href, linkNode);
  235.     return true;
  236.   }
  237.  
  238.   // the rest of the code if for left-click only
  239.  
  240.   /*
  241.    * open targeted links in the current tab only if certain conditions are met.
  242.    * See the function comment for more details.
  243.    *
  244.    */
  245.   if (TMP_divertTargetedLink(event, target, linkNode, openT,
  246.                              document.commandDispatcher.focusedWindow.top.frames,
  247.                              gBrowser.mCurrentTab, currentDomain, targetDomain,
  248.                              targetPref, linkTarget)) {
  249.     return TMP_howToOpen(event, linkNode, true);
  250.   }
  251.  
  252.   /*
  253.    * open links to other sites in a tab only if certain conditions are met. See the
  254.    * function comment for more details.
  255.    *
  256.    */
  257.   if (TMP_openExSiteLink(event, target, linkNode, currentDomain, targetDomain, targetPref)) {
  258.     return TMP_howToOpen(event, linkNode, false);
  259.   }
  260.  
  261.   if (gBrowser.mCurrentTab.hasAttribute("locked")) { // tab is locked
  262.     var href = null, onclick = null;
  263.     if (target.hasAttribute("href")) href = target.getAttribute("href").toLowerCase();
  264.     if (target.hasAttribute("onclick")) onclick = target.getAttribute("onclick");
  265.     if (TMP_checkAttr(href, "javascript:") ||
  266.         TMP_checkAttr(href, "data:") ||
  267.         TMP_checkAttr(onclick, "window.open") ||
  268.         TMP_checkAttr(onclick, "NewWindow") ||
  269.         TMP_checkAttr(onclick, "PopUpWin") ||
  270.         (onclick && onclick.indexOf('this.target="_Blank"') != -1) ||
  271.         TMP_checkAttr(onclick, "return ")) {
  272.       ; // javascript links, do nothing!
  273.     }
  274.     else {
  275.       var current = TMP_checkAttr(href, "#");
  276.       return TMP_howToOpen(event, linkNode, current);
  277.     }
  278.   }
  279.   // use whereToOpenLink() to determine if no modifiers were used
  280.   else if (where == "current") {
  281.       if (fieldNormalClicks && (!openT || openT == "_content" || openT  == "_main"))
  282.         return __contentAreaClick(event, fieldNormalClicks);
  283.       else if (linkNode.hasAttribute("onclick"))
  284.         return __contentAreaClick(event, fieldNormalClicks);
  285.       else if (openT)
  286.         handleLinkClick(event, linkNode.href, linkNode);
  287.     }
  288.   else
  289.       handleLinkClick(event, linkNode.href, linkNode);
  290.  
  291.   return true;
  292. }
  293.  
  294. /**
  295.  * @brief Suppress tabs that may be created by installing Greasemonkey script
  296.  *
  297.  * @returns             true if the link is a script. 
  298.  *
  299.  */
  300. function TMP_isGreasemonkeyScript(event, target) {
  301.   if (event.button == 2)
  302.     return false;
  303.     
  304.   if ("GM_BrowserUI" in window && GM_getEnabled()) {
  305.     var url = target.getAttribute("href");
  306.     if (url && url.match(/\.user\.js(\?|$)/i))
  307.       return true;
  308.   }
  309.   
  310.   return false;
  311. }
  312.  
  313. /**
  314.  * @brief Suppress tabs that may be created by downloading a file.
  315.  *
  316.  * This code borrows from Cusser's Disable Targets for Downloads extension.
  317.  *
  318.  * @param event         A valid event union.
  319.  * @param target        The target of the event.
  320.  * @param linkNode      The DOM node containing the URL to be opened.
  321.  * @param suppressTabs  A Boolean value that controls controlling how the link should be opened.
  322.  * @returns             true if the link was handled by this function.
  323.  *
  324.  */
  325. function TMP_suppressTabsOnFileDownload(event, target, linkNode, suppressTabs) {
  326.    // prevent link with "custombutton" protocol to open new tab when custombutton extension exist
  327.    if (event.button != 2 && typeof(custombuttons) !='undefined'){
  328.       if (TMP_checkAttr(linkNode.toString(), "custombutton://"))
  329.          return true;
  330.    }
  331.  
  332.    if (event.button != 0 || event.ctrlKey || event.metaKey || !suppressTabs)
  333.       return false;
  334.  
  335.    // lets try not to look into links that start with javascript (from 2006-09-02)
  336.    if (TMP_checkAttr(linkNode.toString(), "javascript:"))
  337.       return false;
  338.  
  339.    if (target.hasAttribute("onclick")) {
  340.       var onclick = target.getAttribute("onclick");
  341.       if (TMP_checkAttr(onclick, "return install") ||
  342.           TMP_checkAttr(onclick, "return installTheme") ||
  343.           TMP_checkAttr(onclick, "return note") || TMP_checkAttr(onclick, "return log")) // click on link in http://tinderbox.mozilla.org/showbuilds.cgi
  344.          return true;
  345.    }
  346.  
  347.    // prevent links in tinderbox.mozilla.org with linkHref to *.gz from open in this function
  348.    if (TMP_checkAttr(linkNode.toString() , "http://tinderbox.mozilla.org/showlog") ||
  349.       TMP_checkAttr(linkNode.toString() , "http://tinderbox.mozilla.org/addnote")) return false;
  350.  
  351.    return isUrlForDownload(target.getAttribute("href"))
  352. }
  353.  
  354. function isUrlForDownload(linkHref) {
  355.    //we need this check when calling from onDragOver and onDrop
  356.    if (linkHref.indexOf("mailto:") == 0)
  357.      return true;
  358.  
  359.    var filetype = gTabmixPrefs.getCharPref("extensions.tabmix.filetype");
  360.    filetype = filetype.toLowerCase();
  361.    filetype = filetype.split(" ");
  362.    var linkHrefExt = "";
  363.    if (linkHref) {
  364.       linkHref = linkHref.toLowerCase();
  365.       linkHrefExt = linkHref.substring(linkHref.lastIndexOf("/"),linkHref.length);
  366.       linkHrefExt = linkHrefExt.substring(linkHrefExt.indexOf("."),linkHrefExt.length);
  367.    }
  368.  
  369.    var testString, hrefExt, testExt;
  370.    for (var l = 0; l < filetype.length; l++) {
  371.  
  372.      if (filetype[l].indexOf("/") != -1){
  373.      // add \ before first ?
  374.        testString = filetype[l].substring(1,filetype[l].length-1).replace(/^\?/,"\\?");
  375.        hrefExt = linkHref;
  376.      }
  377.      else {
  378.        testString = "\\." + filetype[l];
  379.        hrefExt = linkHrefExt;
  380.  
  381.        try {
  382.          // prevent filetype catch if it is in the middle of a word
  383.          testExt = new RegExp(testString + "[a-z0-9?\.]+", 'i');
  384.          if (testExt.test(hrefExt))
  385.            continue;
  386.        } catch (ex) {}
  387.      }
  388.      try {
  389.        testExt = new RegExp(testString, 'i');
  390.        if (testExt.test(hrefExt))
  391.          return true;
  392.      } catch (ex) {}
  393.    }
  394.    return false;
  395. }
  396.  
  397. /**
  398.  * @brief Divert middle-clicked links into the current tab.
  399.  *
  400.  * This function forces a middle-clicked link to open in the current tab if
  401.  * the following conditions are true:
  402.  *
  403.  * - links to other sites are not configured to open in new tabs AND the current
  404.  *   page domain and the target page domain do not match OR the current
  405.  *   tab is locked
  406.  * - middle-clicks are configured to open in the current tab AND the middle
  407.  *   mouse button was pressed OR the left mouse button and one of the Ctrl/Meta keys
  408.  *   was pressed
  409.  *
  410.  * @param event            A valid event union.
  411.  * @param linkNode        The DOM node containing the URL to open.
  412.  * @param currentTab        A scripted tab object from the tabbrowser.
  413.  * @param currentDomain        The domain name of the website URL in the current tab.
  414.  * @param targetDomain        The domain name of the website URL in the link node.
  415.  * @param targetPref        An integer value that specifies whether or not links should
  416.  *                be forced into new tabs.
  417.  * @param middlePref        A Boolean value that controls how middle clicks are handled.
  418.  * @returns            true if the function handled the click, false if it didn't.
  419.  *
  420.  */
  421. function TMP_divertMiddleClick(event, linkNode, currentTab, currentDomain, targetDomain,
  422.                                targetPref, middlePref) {
  423.    if (!middlePref)
  424.       return false;
  425.  
  426.    var isTabLocked = currentTab.hasAttribute("locked");
  427.    var isDifDomain = targetPref == 2 && targetDomain &&
  428.                      targetDomain != currentDomain;
  429.    if (!isTabLocked && !isDifDomain)
  430.       return false;
  431.  
  432.    if (event.button == 1 || event.button == 0 && (event.ctrlKey || event.metaKey))
  433.      return true;
  434.  
  435.    return false;
  436. }
  437.  
  438. /**
  439.  * @brief Divert links that contain targets to the current tab.
  440.  *
  441.  * This function forces a link with a target attribute to open in the
  442.  * current tab if the following conditions are true:
  443.  *
  444.  * - linkTarget is set
  445.  * - neither of the Ctrl/Meta keys were used AND the linkNode has a target attribute
  446.  *   AND the content of the target attribute is not one of the special frame targets
  447.  *   AND it is not present in the document frame pool
  448.  * - links to other sites are not configured to open in new tabs AND the domain name
  449.  *   of the current page and the domain name of the target page do not match
  450.  * - the current tab is not locked
  451.  * - the  domain name of the current page and the domain name of the target page
  452.  *   do not match
  453.  * - the target of the event has an onclick attribute that does not contain the
  454.  *   function call 'window.open' or the function call 'return top.js.OpenExtLink'
  455.  *
  456.  * @param event            A valid event union.
  457.  * @param target           The target of the event.
  458.  * @param linkNode         The DOM node containing the URL to be opened.
  459.  * @param targetAttr       The target attribute of the link node.
  460.  * @param frames           The frame pool of the current document.
  461.  * @param currentTab       A scripted tab object from the tabbrowser.
  462.  * @param currentDomain    The domain name of the website URL loaded in the current tab.
  463.  * @param targetDomain     The domain name of the website URL to be loaded.
  464.  * @param targetPref       An integer value that specifies whether or not links should
  465.  *                         be forced into new tabs.
  466.  * @param linkTarget       An integer value that specifies how normal links
  467.  *                         that spawn new windows are handled.
  468.  * @returns                true if the function handled the click, false if it didn't.
  469.  *
  470.  */
  471. function TMP_divertTargetedLink(event, target, linkNode, targetAttr, frames,
  472.                                 currentTab, currentDomain, targetDomain,
  473.                                 targetPref, linkTarget) {
  474.   if (!linkTarget) return false;
  475.   if (TMP_checkAttr(linkNode.toString(), "javascript:") || // 2005-11-28 some link in Bloglines start with javascript
  476.       TMP_checkAttr(linkNode.toString(), "data:"))
  477.     return false;
  478.  
  479.   if (event.ctrlKey || event.metaKey) return false;
  480.  
  481.   if (!targetAttr) return false;
  482.   var targetString = /^(_self|_parent|_top|_content|_main)$/;
  483.   if (targetString.test(targetAttr.toLowerCase())) return false;
  484.  
  485.   if (TMP_existsFrameName(frames, targetAttr)) return false;
  486.  
  487.   if (targetPref == 2 && targetDomain && targetDomain != currentDomain) return false;
  488.   if (currentTab.hasAttribute("locked")) return false;
  489.   if (targetDomain && targetDomain == currentDomain) return false;
  490.  
  491.   if (target.hasAttribute("onclick")) {
  492.     var onclick = target.getAttribute("onclick");
  493.     if (TMP_checkAttr(onclick, "window.open") ||
  494.         TMP_checkAttr(onclick, "NewWindow") ||
  495.         TMP_checkAttr(onclick, "PopUpWin") ||
  496.         TMP_checkAttr(onclick, "return "))
  497.           return false;
  498.   }
  499.  
  500.   return true;
  501. }
  502.  
  503. /**
  504.  * @brief Open links to other sites in tabs as directed.
  505.  *
  506.  * This function opens links to external sites in tabs as long as the following
  507.  * conditions are met:
  508.  *
  509.  * - links to other sites are configured to open in tabs
  510.  * - the link node does not have an 'onclick' attribute that contains either the function call
  511.  *   'window.open' or the function call 'return top.js.OpenExtLink'.
  512.  * - the domain name of the current page and the domain name of the target page do not match
  513.  *   OR the link node has an 'onmousedown' attribute that contains the text 'return rwt'
  514.  *
  515.  * @param event             A valid event union.
  516.  * @param target           The target of the event.
  517.  * @param linkNode         The DOM node containing the URL to be opened.
  518.  * @param currentDomain    The domain name of the website URL loaded in the current tab.
  519.  * @param targetDomain     The domain name of the website URL to be loaded.
  520.  * @param targetPref       An integer value that specifies whether or not links should
  521.  *                         be forced into new tabs.
  522.  * @returns                true if the function handled the click, false if it didn't.
  523.  *
  524.  */
  525. function TMP_openExSiteLink(event, target, linkNode, currentDomain, targetDomain, targetPref) {
  526.   if (targetPref != 2) return false;
  527.  
  528.   if (target.hasAttribute("onclick")) {
  529.     var onclick = target.getAttribute("onclick");
  530.     if (TMP_checkAttr(onclick, "window.open") ||
  531.         TMP_checkAttr(onclick, "NewWindow") ||
  532.         TMP_checkAttr(onclick, "PopUpWin") ||
  533.         TMP_checkAttr(onclick, "return "))
  534.             return false;
  535.   }
  536.   if (targetDomain && targetDomain != currentDomain ||
  537.      TMP_checkAttr(target.getAttribute("onmousedown"), "return rwt"))
  538.     return true;
  539.  
  540.   return false;
  541. }
  542.  
  543. /**
  544.  * @brief Check a document's frame pool and determine if
  545.  * |targetFrame| is located inside of it.
  546.  *
  547.  * @param containerFrame    The frame pool of the current document.
  548.  * @param targetFrame        The name of the frame that we are seeking.
  549.  * @returns            true if the frame exists within the given frame pool,
  550.  *                false if it does not.
  551.  */
  552. function TMP_existsFrameName(containerFrame, targetFrame) {
  553.     for (var i = 0; i < containerFrame.length; ++i) {
  554.           if (containerFrame[i].name == targetFrame) return true;
  555.           if (containerFrame[i].frames.length) var return_var = TMP_existsFrameName(containerFrame[i].frames,targetFrame);
  556.     }
  557.  
  558.     if (return_var) return return_var;
  559.     return false;
  560. }
  561.  
  562. /**
  563.  * @brief Locate a browser window.
  564.  *
  565.  * @param aExclude    A scripted window object that we do not
  566.  *            want to use.
  567.  * @returns        A scripted window object representing a browser
  568.  *            window that is not the same as aExclude, and is
  569.  *            additionally not a popup window.
  570.  *
  571.  */
  572. function TMP_getBrowserWindow(aExclude) {
  573.     var windows = gWindowManager.getEnumerator('navigator:browser');
  574.  
  575.     while (windows.hasMoreElements()) {
  576.         var win = windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindow);
  577.         if (TMP_checkForPopup(win.QueryInterface(Components.interfaces.nsIDOMWindowInternal)))
  578.             continue;
  579.  
  580.         // this returns the first window that we find; it is not exhaustive
  581.         if (win != aExclude) return win;
  582.     }
  583.     return null;
  584. }
  585.  
  586. /**
  587.  * @brief Checks to see if a given nsIDOMWindowInternal window is a popup or not.
  588.  *
  589.  * @param domWindow       A scripted nsIDOMWindowInternal object.
  590.  * @return           true if the domWindow is a popup, false otherwise.
  591.  *
  592.  */
  593. function TMP_checkForPopup(domWindow) {
  594.   if (!(domWindow instanceof Components.interfaces.nsIDOMWindowInternal)) return false;
  595.  
  596.   // FIXME: locationbar, menubar, toolbar -
  597.   // if these are hidden the window is probably a popup
  598.   var locbarHidden = !domWindow.locationbar.QueryInterface(Components.interfaces.nsIDOMBarProp).visible;
  599.   var menubarHidden = !domWindow.menubar.QueryInterface(Components.interfaces.nsIDOMBarProp).visible;
  600.   try {
  601.      var toolbarHidden = !domWindow.toolbar.QueryInterface(Components.interfaces.nsIDOMBarProp).visible;
  602.   }
  603.   catch (e) {
  604.    toolbarHidden = "hidden" in domWindow.toolbar ? domWindow.toolbar.hidden : false;
  605.   }
  606.  
  607.   // the following logic, while possibly slow, is designed
  608.   // to catch all reasonable permutations of hidden UI
  609.   if ((locbarHidden && menubarHidden) ||
  610.       (menubarHidden && toolbarHidden) ||
  611.       (locbarHidden && menubarHidden && toolbarHidden)) {
  612.     return true;
  613.   }
  614.  
  615.   return false;
  616. }
  617.  
  618. /*
  619.  * handle all DOM window open events and catch attempts to open new windows
  620.  *
  621.  * PRECONDITION: None.
  622.  * POSTCONDITION: None.
  623.  *
  624.  */
  625. var TMP_DOMWindowOpenObserver = {
  626.     Tbplite: 'tbpl',
  627.  
  628.     observe : function(aSubject, aTopic, aData) {
  629.         if (aTopic != 'domwindowopened') return;
  630.         this.onObserve(aSubject, this);
  631.         return;
  632.     },
  633.  
  634.     onObserve : function(aSubject, aThis) {
  635.         gSingleWindowMode = TMP_getBoolPref(tabxBranch, "singleWindow", false);
  636.         gTMPprefObserver.setLink_openPrefs();
  637.         if (!gSingleWindowMode)
  638.           return;
  639.  
  640.         var newWindow = aSubject;
  641.         var existingWindow = TMP_getBrowserWindow(newWindow);
  642.  
  643.         // no navigator:browser window open yet?
  644.         if (!existingWindow) return;
  645.  
  646.         // if the href is missing, try again later (xxx)
  647.         if (!newWindow.location.href) {
  648.             existingWindow.setTimeout(aThis.onObserve, 0, newWindow, aThis);
  649.             return;
  650.         }
  651.  
  652.         // we don't want to open non-browser windows in a tab
  653.         if(newWindow.location.href != "chrome://browser/content/browser.xul")
  654.             return;
  655.  
  656.         if ( !('arguments' in newWindow) || newWindow.arguments.length == 0 )
  657.           return;
  658.  
  659.         // we can get here before BrowserStartup use getBrowser() for Firefox 3.0
  660.         var existingBrowser = existingWindow.getBrowser();
  661.         existingWindow.tablib.init(); // just incase tablib isn't init yet
  662.         var uriToLoad = newWindow.arguments[0];
  663.         if (uriToLoad instanceof Components.interfaces.nsISupportsArray) {
  664.            var count = uriToLoad.Count();
  665.            var specs = [];
  666.            for (var i = 0; i < count; i++) {
  667.               var urisstring = uriToLoad.GetElementAt(i).QueryInterface(Components.interfaces.nsISupportsString);
  668.               specs.push(urisstring.data);
  669.            }
  670.            try {
  671.               existingBrowser.loadTabs(specs, false, false);
  672.            } catch (e) {}
  673.         }
  674.         else if (uriToLoad instanceof XULElement) {
  675.           // some extension try to swap a tab to new window
  676.           // we don't do anything in this case.
  677.           // just close the new window
  678.         }
  679.         else if (newWindow.arguments.length >= 3) {
  680.            var newTab = existingBrowser.addTab(uriToLoad, newWindow.arguments[2], null,
  681.                             newWindow.arguments[3] || null, null, newWindow.arguments[4] || false);
  682.            existingBrowser.TMP_selectNewForegroundTab(newTab, false, uriToLoad);
  683.         }
  684.         else {
  685.            try {
  686.               existingBrowser.loadTabs(uriToLoad.split("|"), false, false);
  687.            } catch (e) {}
  688.         }
  689.  
  690.         setTimeout(newWindow.close, 0);
  691.         return;
  692.     }
  693. }
  694. // end of TMP_DOMWindowOpenObserver
  695.